/**
 * Project 67th
 */


#include "Eventfd.h"
#include <unistd.h>
#include <stdio.h>
#include <poll.h>
#include <sys/eventfd.h>
#include <errno.h>
#include <iostream>
using std::cout;
using std::endl;

/**
 * Eventfd implementation
 */


/**
 * @param cb
 */
Eventfd::Eventfd(EventfdCallback && cb) 
    : _evtfd(createEventFd())
    , _cb(std::move(cb))
      , _isStarted(false)
{

}

Eventfd::~Eventfd() {
    close(_evtfd);
}

/**
 * @return void
 */
void Eventfd::start() {
    struct pollfd pfd;
    pfd.fd = _evtfd;//监听代表计数器的文件描述符
    pfd.events = POLLIN;

    _isStarted = true;
    while(_isStarted)
    {
        int nready = poll(&pfd,1,5000);
        if(-1 == nready && errno == EINTR)
        {
            continue;
        }
        else if(-1 == nready)
        {
            perror("poll");
        }
        else if(0 == nready)
        {
            cout << " >> poll timeout!" << endl;
        }
        else
        {
            //线程A监听eventfd
            //如果发现eventfd就绪，而且确实是读事件
            //那么说明其他的线程对计数器进行了write
            //也就是线程A收到通知
            //对计数器执行一次读操作，然后再执行任务
            if(pfd.revents & POLLIN)
            {
                handleRead();
                if(_cb)
                {
                    _cb();
                }
            }
        }
    }

}

/**
 * @return void
 */
void Eventfd::stop() {
    _isStarted = false;
}

/**
 * @return int
 */
int Eventfd::createEventFd() {
    int fd = eventfd(0,0);
    if(fd == -1)
    {
        perror("createEventfd");   
        return -1;
    }

    return fd;
}

/**
 * @return void
 */
void Eventfd::handleRead() {
    uint64_t u = 1;
    ssize_t s = read(_evtfd, &u, sizeof(uint64_t));
    if (s != sizeof(uint64_t))
    {
        perror("wakeup");
    }
}

/**
 * @return void
 */
void Eventfd::wakeup() {
    uint64_t u = 1;
    ssize_t s = write(_evtfd, &u, sizeof(uint64_t));
    if (s != sizeof(uint64_t))
    {
        perror("wakeup");
    }
}
